/* DOES NOT USE BUILT-IN DETECTION ENGINE
alert tcp $EXTERNAL_NET $HTTP_PORTS -> $HOME_NET any (msg:"WEB-CLIENT OpenType Font file parsing buffer overflow attempt"; flow:to_client,established; flowbits:isset,file.otf; content:"name"; content:"|00 03 00 01|"; distance:0; metadata:policy balanced-ips drop, policy security-ips drop, service http; reference:cve,2010-2740; reference:url,technet.microsoft.com/en-us/security/bulletin/MS10-078; classtype:attempted-user; sid:1234;)
*/
/*
 * This code was automatically generated by the Sourcefire VRT Rules2C web generator
 *
 * We make no claims to the correctness or fitness of the code generated or of modifications
 * to the generated code.
 *
 * Use at your own risk.
 *
 * Please report any problems with this tool to research@sourcefire.com
 */

#include "sf_snort_plugin_api.h"
#include "sf_snort_packet.h"

//#define DEBUG
#ifdef DEBUG
#define DEBUG_WRAP(code) code
#else
#define DEBUG_WRAP(code)
#endif

/* declare detection functions */
int rule17765eval(void *p);

/* declare rule data structures */
/* flow:established, to_client; */
static FlowFlags rule17765flow0 = 
{
    FLOW_ESTABLISHED|FLOW_TO_CLIENT
};

static RuleOption rule17765option0 =
{
    OPTION_TYPE_FLOWFLAGS,
    {
        &rule17765flow0
    }
};
/* flowbits:isset "file.otf"; */
static FlowBitsInfo rule17765flowbits1 =
{
    "file.otf",
    FLOWBIT_ISSET,
    0,
};

static RuleOption rule17765option1 =
{
    OPTION_TYPE_FLOWBIT,
    {
        &rule17765flowbits1
    }
};
// content:"name", payload raw, depth 0, fast_pattern; 
static ContentInfo rule17765content2 = 
{
    (uint8_t *) "name", /* pattern (now in snort content format) */
    0, /* depth */
    0, /* offset */
    CONTENT_FAST_PATTERN|CONTENT_BUF_NORMALIZED, /* flags */
    NULL, /* holder for boyer/moore PTR */
    NULL, /* more holder info - byteform */
    0, /* byteform length */
    0 /* increment length*/
};

static RuleOption rule17765option2 = 
{
    OPTION_TYPE_CONTENT,
    {
        &rule17765content2
    }
};
// content:"|00 03 00 01|", payload raw, depth 0, relative; 
static ContentInfo rule17765content3 = 
{
    (uint8_t *) "|00 03 00 01|", /* pattern (now in snort content format) */
    0, /* depth */
    0, /* offset */
    CONTENT_RELATIVE|CONTENT_BUF_NORMALIZED, /* flags */
    NULL, /* holder for boyer/moore PTR */
    NULL, /* more holder info - byteform */
    0, /* byteform length */
    0 /* increment length*/
};

static RuleOption rule17765option3 = 
{
    OPTION_TYPE_CONTENT,
    {
        &rule17765content3
    }
};

/* references for sid 17765 */
/* reference: cve "2010-2740"; */
static RuleReference rule17765ref1 = 
{
    "cve", /* type */
    "2010-2740" /* value */
};

/* reference: url "technet.microsoft.com/en-us/security/bulletin/MS10-078"; */
static RuleReference rule17765ref2 = 
{
    "url", /* type */
    "technet.microsoft.com/en-us/security/bulletin/MS10-078" /* value */
};

static RuleReference *rule17765refs[] =
{
    &rule17765ref1,
    &rule17765ref2,
    NULL
};
/* metadata for sid 17765 */
/* metadata:service http, policy balanced-ips drop, policy security-ips drop; */
static RuleMetaData rule17765service1 = 
{
    "service http"
};


//static RuleMetaData rule17765policy1 = 
//{
//    "policy balanced-ips drop"
//};
//
//static RuleMetaData rule17765policy2 = 
//{
//    "policy security-ips drop"
//};

static RuleMetaData rule17765policy3 = 
{
    "policy max-detect-ips drop"
};

static RuleMetaData *rule17765metadata[] =
{
    &rule17765service1,
//    &rule17765policy1,
//    &rule17765policy2,
    &rule17765policy3,
    NULL
};

RuleOption *rule17765options[] =
{
    &rule17765option0,
    &rule17765option1,
    &rule17765option2,
    &rule17765option3,
    NULL
};

Rule rule17765 = {
   /* rule header, akin to => tcp any any -> any any */
   {
       IPPROTO_TCP, /* proto */
       "$EXTERNAL_NET", /* SRCIP     */
       "$HTTP_PORTS", /* SRCPORT   */
   
       0, /* DIRECTION */
       "$HOME_NET", /* DSTIP     */
   
       "any", /* DSTPORT   */
   },
   /* metadata */
   { 
       3,  /* genid */
       17765, /* sigid */
       6, /* revision */
       "attempted-user", /* classification */
       0,  /* hardcoded priority XXX NOT PROVIDED BY GRAMMAR YET! */
       "OS-WINDOWS OpenType Font file parsing buffer overflow attempt",     /* message */
       rule17765refs /* ptr to references */
       ,rule17765metadata
   },
   rule17765options, /* ptr to rule options */
   &rule17765eval, /* replace with NULL to use the built in detection function */
   0 /* am I initialized yet? */
};


/* detection functions */
int rule17765eval(void *p) {
    const uint8_t *cursor_normal = 0;
    SFSnortPacket *sp = (SFSnortPacket *) p;
    const uint8_t *beg_of_payload, *end_of_payload;
    uint16_t length;
    uint32_t name_table_offset = 0;
    uint32_t name_table_length = 0;
    const uint8_t *end_of_name_table = 0;

    if(sp == NULL)
        return RULE_NOMATCH;

    // flow:established, to_client;
    if (checkFlow(p, rule17765options[0]->option_u.flowFlags) <= 0)
        return RULE_NOMATCH;
 
    // flowbits:isset "file.otf";
    if (processFlowbits(p, rule17765options[1]->option_u.flowBit) <= 0)
        return RULE_NOMATCH;
    
    // content:"name", payload raw, depth 0, fast_pattern;
    if (contentMatch(p, rule17765options[2]->option_u.content, &cursor_normal) <= 0)
        return RULE_NOMATCH;
 
    if (getBuffer(sp, CONTENT_BUF_NORMALIZED, &beg_of_payload, &end_of_payload) <= 0)
        return RULE_NOMATCH;
    
    if(cursor_normal + 12 >= end_of_payload)
        return RULE_NOMATCH;
    
    /* Move the cursor forward 4 bytes   */
    cursor_normal += 4;

    /* Get the offset for the Name table (offset is from the beginning of the TrueType font file)   */ 
    name_table_offset = (*cursor_normal++) << 24;
    name_table_offset |= (*cursor_normal++) << 16;
    name_table_offset |= (*cursor_normal++) << 8;
    name_table_offset |= *cursor_normal++;
    
    /* Get the length for the Name table    */
    name_table_length = (*cursor_normal++) << 24;
    name_table_length |= (*cursor_normal++) << 16;
    name_table_length |= (*cursor_normal++) << 8;
    name_table_length |= *cursor_normal++;

    DEBUG_WRAP(printf("TABLE OFFSET: %x\n", name_table_offset));
    DEBUG_WRAP(printf("TABLE LENGTH: %x\n", name_table_length));

    /* Move to the beginning of Name table    */
    cursor_normal = beg_of_payload + name_table_offset;

    /* Set the end of the name table    */
    end_of_name_table = cursor_normal + name_table_length;

    if(end_of_name_table > end_of_payload || end_of_name_table < cursor_normal)
        end_of_name_table = end_of_payload;

    /* While we haven't hit either the end of the name table or the end of the payload    */ 
    while (cursor_normal < end_of_name_table) {
        /* Look for a Name Record with a PlaformID of 3 and an encodingID of 1    */
        // content:"|00 03 00 01|", payload raw, depth 0, relative;
        if (contentMatch(p, rule17765options[3]->option_u.content, &cursor_normal) <= 0)
            return RULE_NOMATCH;
 
        /* Check to see if there is data a few bytes ahead    */
        if(cursor_normal + 6 >= end_of_name_table)
            return RULE_NOMATCH;

        /* Move the cursor forward    */
        cursor_normal += 5;

        if ((*cursor_normal) & 0x01)
            return RULE_MATCH;
        else
            cursor_normal += 2;

    }
return RULE_NOMATCH;
}

/*
Rule *rules[] = {
    &rule17765,
    NULL
};
*/
